/**
 * 文件压缩功能
 * @param {File} file - 要压缩的文件
 * @param {number} [maxSize=10] - 最大文件大小（单位：MB），默认10MB
 * @param {Object} [uploadConfig] - 上传配置（可选）
 * @param {string} uploadConfig.url - 上传地址
 * @param {Object} [uploadConfig.headers] - 请求头
 * @param {Object} [uploadConfig.data] - 额外的表单数据
 * @param {string} [uploadConfig.filename='file'] - 文件字段名
 * @returns {Promise<{file: File, response?: any}>} - 返回压缩后的文件和上传响应（如果有上传）
 */
const compressFile = async (file, maxSize = 10, uploadConfig = null) => {
  // 将 MB 转换为 bytes 进行比较
  const maxSizeInBytes = maxSize * 1024 * 1024;

  // 如果文件大小未超过限制，直接返回原文件
  if (file.size <= maxSizeInBytes) {
    const result = { file };
    if (uploadConfig) {
      result.response = await uploadFile(file, uploadConfig);
    }
    return result;
  }

  // 根据文件类型选择不同的压缩方法
  const fileType = file.type.split('/')[0];
  let compressedFile;

  switch (fileType) {
    case 'image':
      compressedFile = await compressImage(file, maxSizeInBytes);
      break;
    case 'video':
      compressedFile = await compressVideo(file, maxSizeInBytes);
      break;
    case 'application':
    case 'text':
      compressedFile = await compressOtherFile(file, maxSizeInBytes);
      break;
    default:
      throw new Error('不支持的文件类型');
  }

  const result = { file: compressedFile };
  if (uploadConfig) {
    result.response = await uploadFile(compressedFile, uploadConfig);
  }
  return result;
};

/**
 * 上传文件
 * @param {File} file - 要上传的文件
 * @param {Object} config - 上传配置
 * @returns {Promise<any>} - 上传响应
 */
const uploadFile = async (file, config) => {
  const formData = new FormData();
  const filename = config.filename || 'file';

  // 添加文件
  formData.append(filename, file);

  // 添加其他表单数据
  if (config.data) {
    Object.entries(config.data).forEach(([key, value]) => {
      formData.append(key, value);
    });
  }

  try {
    const response = await fetch(config.url, {
      method: 'POST',
      headers: config.headers || {},
      body: formData
    });

    if (!response.ok) {
      throw new Error(`上传失败: ${response.status} ${response.statusText}`);
    }

    return await response.json();
  } catch (error) {
    throw new Error(`上传出错: ${error.message}`);
  }
};

/**
 * 图片压缩
 */
const compressImage = async (file, maxSizeInBytes) => {
  const image = new Image();
  const reader = new FileReader();

  return new Promise((resolve, reject) => {
    reader.onload = (e) => {
      image.src = e.target.result;
      image.onload = () => {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');

        let width = image.width;
        let height = image.height;
        let quality = 0.9;

        // 如果图片尺寸太大，先进行尺寸压缩
        const maxDimension = 2048;
        if (width > maxDimension || height > maxDimension) {
          if (width > height) {
            height = Math.round((height * maxDimension) / width);
            width = maxDimension;
          } else {
            width = Math.round((width * maxDimension) / height);
            height = maxDimension;
          }
        }

        canvas.width = width;
        canvas.height = height;
        ctx.drawImage(image, 0, 0, width, height);

        const compress = () => {
          canvas.toBlob(
            (blob) => {
              if (blob.size > maxSizeInBytes && quality > 0.1) {
                quality -= 0.1;
                compress();
                return;
              }

              const compressedFile = new File([blob], file.name, { type: file.type });

              // 如果压缩到最小质量后仍然超过限制
              if (blob.size > maxSizeInBytes && quality <= 0.1) {
                if (confirm(`文件已压缩到最小（${(blob.size / (1024 * 1024)).toFixed(2)}MB），但仍超过限制（${(maxSizeInBytes / (1024 * 1024)).toFixed(2)}MB）。\n是否继续使用此文件？`)) {
                  resolve(compressedFile);
                } else {
                  reject(new Error('用户取消使用超限文件'));
                }
                return;
              }

              resolve(compressedFile);
            },
            file.type,
            quality
          );
        };

        compress();
      };
    };
    reader.onerror = (error) => reject(error);
    reader.readAsDataURL(file);
  });
};

/**
 * 视频压缩
 */
const compressVideo = async (file, maxSizeInBytes) => {
  return new Promise((resolve, reject) => {
    try {
      // 创建视频元素
      const video = document.createElement('video');
      video.src = URL.createObjectURL(file);

      video.onloadedmetadata = () => {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');

        // 设置压缩后的视频尺寸
        const maxWidth = 1280;
        const maxHeight = 720;
        let width = video.videoWidth;
        let height = video.videoHeight;

        if (width > maxWidth || height > maxHeight) {
          if (width > height) {
            height = Math.round((height * maxWidth) / width);
            width = maxWidth;
          } else {
            width = Math.round((width * maxHeight) / height);
            height = maxHeight;
          }
        }

        canvas.width = width;
        canvas.height = height;

        // 使用 MediaRecorder 压缩视频
        const stream = canvas.captureStream();
        const mediaRecorder = new MediaRecorder(stream, {
          mimeType: 'video/webm;codecs=vp9',
          videoBitsPerSecond: 1000000 // 1Mbps
        });

        const chunks = [];
        mediaRecorder.ondataavailable = (e) => chunks.push(e.data);
        mediaRecorder.onstop = () => {
          const blob = new Blob(chunks, { type: 'video/webm' });
          const compressedFile = new File([blob], file.name.replace(/\.[^/.]+$/, '.webm'), {
            type: 'video/webm'
          });

          // 如果压缩后仍然超过限制
          if (blob.size > maxSizeInBytes) {
            if (confirm(`视频已压缩（${(blob.size / (1024 * 1024)).toFixed(2)}MB），但仍超过限制（${(maxSizeInBytes / (1024 * 1024)).toFixed(2)}MB）。\n是否继续使用此文件？`)) {
              resolve(compressedFile);
            } else {
              reject(new Error('用户取消使用超限文件'));
            }
            return;
          }

          resolve(compressedFile);
        };

        video.play();
        mediaRecorder.start();

        // 录制指定时长后停止
        setTimeout(() => {
          mediaRecorder.stop();
          video.pause();
        }, video.duration * 1000);

        // 每帧绘制视频
        const drawVideo = () => {
          if (video.ended || video.paused) return;
          ctx.drawImage(video, 0, 0, width, height);
          requestAnimationFrame(drawVideo);
        };
        drawVideo();
      };
    } catch (error) {
      reject(new Error('视频压缩失败：' + error.message));
    }
  });
};

/**
 * 其他文件压缩（使用 CompressionStream API）
 */
const compressOtherFile = async (file, maxSizeInBytes) => {
  try {
    const compressed = new Blob([file]).stream().pipeThrough(new CompressionStream('gzip'));
    const blob = await new Response(compressed).blob();
    const compressedFile = new File([blob], file.name + '.gz', {
      type: 'application/gzip'
    });

    // 如果压缩后仍然超过限制
    if (blob.size > maxSizeInBytes) {
      if (confirm(`文件已压缩（${(blob.size / (1024 * 1024)).toFixed(2)}MB），但仍超过限制（${(maxSizeInBytes / (1024 * 1024)).toFixed(2)}MB）。\n是否继续使用此文件？`)) {
        return compressedFile;
      } else {
        throw new Error('用户取消使用超限文件');
      }
    }

    return compressedFile;
  } catch (error) {
    throw new Error('文件压缩失败：' + error.message);
  }
};

export default compressFile;